package cn.kgc.javaweb.servlet;

import cn.hutool.captcha.LineCaptcha;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import cn.kgc.javaweb.entity.User;
import cn.kgc.javaweb.service.UserService;
import cn.kgc.javaweb.service.impl.UserServiceImpl;
import cn.kgc.javaweb.utils.ResponseResult;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * @author: mosin
 * @version: v1.0  2022/9/8
 * 编写所有的用户请求方法
 * /user?method= ?
 * 用户的注册       /user?method= register
 * 登录：          /user?method= login
 * 添加            /user?method= add
 * 删除            /user?method= delete
 * 更新            /user?method= update
 * 查询            /user?method= select
 */
@WebServlet("/user")
public class UserServlet extends HttpServlet {

    //注入用户的业务层对象
    private UserService userService = new UserServiceImpl();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //设置请求的编码格式
        req.setCharacterEncoding("UTF-8");
        // 获取用户的请求路径
        String method = req.getParameter("method");
        // 请求的分发
        switch (method) {
            case "login":
                login(req, resp);
                break;
            case "logout":
                logout(req, resp);
                break;
            case "register":
                register(req, resp);
                break;
            case "checkUsername":
                checkUsername(req, resp);
                break;
            case "getCode":
                getCode(req, resp);
                break;
            case "selectAll":
                selectAll(req, resp);
                break;
            case "add":
                add(req, resp);
                break;
            case "delete":
                delete(req, resp);
                break;
            case "toUpdate":
                toUpdate(req, resp);
                break;
            case "update":
                update(req, resp);
                break;
            case "selectPage":
                selectPage(req, resp);
                break;
            case "upload":
                upload(req, resp);
                break;
            case "download":
                download(req, resp);
                break;
        }

    }

    //退出登录
    protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{

        // 退出登录  销毁当前请求对应session对象  用户再次发送请求时 需要再次认证
        HttpSession session = req.getSession();
        session.invalidate();

        // 跳转页面到登录页
        resp.sendRedirect(req.getContextPath()+"/login.jsp");

    }

    // 文件的下载
    protected  void download(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {

        // 获取参数  下载的头像的名字
        String img = req.getParameter("img");
        // 创建输入流读取文件
        File file = new File("D:\\upload\\", img);
        FileInputStream fileInputStream = new FileInputStream(file);

        // 如果想实现文件以附件的形式进行下载 需要设置响应头 设置以附件形式打开  attachment 附件   filename 下载完成后文件的名字
        //resp.setHeader("Content-Disposition", "attachment; filename="+img);

        // 获取输出流 将图片写出
        ServletOutputStream outputStream = resp.getOutputStream();
        // 使用工具类  实现流的对拷
        IOUtils.copy(fileInputStream, outputStream);
        // 释放资源
        outputStream.close();
        fileInputStream.close();
    }

    //修改头像  文件上传
    protected void upload(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 创建 fileItemFactory工厂对象
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
        // 通过servletFileUpload 对象 解析请求对象 获取请求参数
        try {
            // 返回数据时表单中提交的数据  封装成了FileItem 类型的数据  input
            List<FileItem> fileItems = servletFileUpload.parseRequest(req);
            // 遍历集合  上传文件
            for (FileItem fileItem : fileItems) {
                /*
                 * 文件上传时  解决文件名字重复的问题  UUID
                 * 1.获取文件的名称 1.jpg  2.png
                 * 2. 截取文件的扩展名  .jpg  .png
                 * 3.拼接文件的名字 uuid + 扩展名
                 * 4.调用方法实现文件上传
                 * */
                // 1. 获取文件名  a.jpg
                String fileName = fileItem.getName();
                // 获取文件扩展名
                String fileExtension = fileName.substring(fileName.lastIndexOf("."));
                //生成uuid  xxx-xxxxx-xxx  ->xxxxx
                String s = UUID.randomUUID().toString();
                System.out.println("s = " + s);
                String uuid = s.replace("-", "");
                System.out.println("uuid = " + uuid);
                //拼接文件名
                String lastName = uuid+fileExtension;
                File file = new File("D:\\upload\\", lastName);
                try {
                    fileItem.write(file);
                    System.out.println("文件上传成功");
                    //将头像的名字保存到数据库中  根据用户id  修改 img字段
                    HttpSession session = req.getSession();
                    User user = (User) session.getAttribute("user");
                    Integer userId = user.getId();
                    userService.updateImg(userId,lastName);

                    // 更新成功  跳转主页面  更新 session中存储的用户信息
                    user.setImg(lastName);
                    // 覆盖session中原有的 user
                    session.setAttribute("user", user);
                    resp.sendRedirect(req.getContextPath()+"/user?method=selectPage&page=1");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }


    }

    // 分页查询
    protected void selectPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取请求参数
        Integer page = Integer.valueOf(req.getParameter("page"));
        //定义变量 存储每页显示的条数
        Integer size = 5;
        // 调用业务层进行分页查询
        ResponseResult responseResult = userService.selectByPage(page, size);
        System.out.println("responseResult = " + responseResult);
        //将查询的结果放入 request作用域  进行页面的转发
        req.setAttribute("result", responseResult);
        req.getRequestDispatcher("/index.jsp").forward(req, resp);
    }

    //更新用户信息
    protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数
        int id = Integer.parseInt(req.getParameter("id"));
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String tel = req.getParameter("tel");
        String birth = req.getParameter("birth");

        //数据的封装  方便数据的传递
        User user = new User();
        user.setId(id);
        user.setUsername(username);

        //根据用户名字 查询用户信息 判定用户密码是否被修改
        User usr = userService.selectUpdateUser(username);
        if (usr.getPassword().equals(password)) {
            user.setPassword(password);
        } else {
            user.setPassword(SecureUtil.md5(password));
        }

        user.setTel(tel);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date bir = sdf.parse(birth);
            user.setBirth(bir);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //更新用户数据
        userService.updateUser(user);
        //跳转页面到index.jsp   1.重新查询数据库   /user?method=selectAll 得到最新的用户信息  2.通过转发 到达index.jsp
        //resp.sendRedirect(req.getContextPath() + "/user?method=selectAll");
        resp.sendRedirect(req.getContextPath() + "/user?method=selectPage&page=1");
    }

    // 根据用户名查询用户信息 跳转更新页
    protected void toUpdate(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取请求参数用户名
        String username = req.getParameter("username");
        User user = userService.selectUpdateUser(username);
        req.setAttribute("user", user);
        req.getRequestDispatcher("/update.jsp").forward(req, resp);
    }

    //根据ID删除用户信息
    protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        int id = Integer.parseInt(req.getParameter("id"));
        //调用业务层删除用户信息
        userService.delete(id);


        // 将用户对应的session销毁  hashmap中获取删除id 对应的session
        ServletContext servletContext = req.getSession().getServletContext();
        HashMap<Integer,HttpSession> hashmap = (HashMap<Integer, HttpSession>) servletContext.getAttribute("hashmap");

        HttpSession httpSession = hashmap.get(id);
        if(httpSession!=null){
            httpSession.invalidate();
            hashmap.remove(id);
        }
        //页面跳转
        //resp.sendRedirect(req.getContextPath() + "/user?method=selectAll");
        // 页面跳转实现分页
        resp.sendRedirect(req.getContextPath() + "/user?method=selectPage&page=1");

    }

    //添加用户 一般是管理员调用的接口
    protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取请求参数
        String username = req.getParameter("username");
        String password = SecureUtil.md5(req.getParameter("password"));
        String tel = req.getParameter("tel");
        String birth = req.getParameter("birth");


        //数据的封装  方便数据的传递
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setTel(tel);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date bir = sdf.parse(birth);
            user.setBirth(bir);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //添加用户 可以没有返回值  一旦添加出现异常 直接跳转错误页
        userService.add(user);

        //跳转页面到index.jsp   1.重新查询数据库   /user?method=selectAll 得到最新的用户信息  2.通过转发 到达index.jsp
        //resp.sendRedirect(req.getContextPath() + "/user?method=selectAll");

        resp.sendRedirect(req.getContextPath() + "/user?method=selectPage&page=1");
    }

    //查询所有用户信息 展示在index.jsp
    protected void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // TODO  查询数据库
        ResponseResult responseResult = userService.selectAll();
        req.setAttribute("result", responseResult);
        req.getRequestDispatcher("/index.jsp").forward(req, resp);
    }

    //生成验证码
    protected void getCode(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //hutool工具类 生成验证码  参数1：图片宽度  参数2 图片的高度  参数3 验证码的个数   参数4  干扰线的条数
        LineCaptcha lineCaptcha = new LineCaptcha(90, 50, 4, 2);
        // 获取生成的验证码
        String code = lineCaptcha.getCode();
        System.out.println("code = " + code);

        // 保存验证码  session
        HttpSession session = req.getSession();
        session.setAttribute("code", code);

        //通过输出流 响应验证码
        ServletOutputStream outputStream = resp.getOutputStream();
        lineCaptcha.write(outputStream);
        // 释放资源
        outputStream.close();
    }

    //用户名的验重
    protected void checkUsername(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取请求参数
        String username = req.getParameter("username");

        //根据用户名查询用户信息   查询数据库   UserService
        Boolean b = userService.selectByUsername(username);

        //根据查询的结果  响应数据给前端浏览器

        ResponseResult responseResult = new ResponseResult();
        if (b) {
            //用户名可用
            responseResult.setMsg("用户名可用");
        } else {
            responseResult.setCode(500);
            responseResult.setMsg("用户名已被占用");
        }

        // 前端需要响应的数据类型是json格式    responseResult  java对象   -> json字符串
        String s = JSONUtil.toJsonStr(responseResult);
        //设置响应的格式为json格式
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.write(s);
        writer.close();
    }

    //注册方法
    protected void register(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String username = req.getParameter("username");
        // 密码加密
        String password = SecureUtil.md5(req.getParameter("password"));

        //将用户名和密码写入数据库 进行数据的持久化操作
        userService.register(username, password);

        // 页面跳转  重定向
        resp.sendRedirect(req.getContextPath() + "/login.jsp");
    }

    //登录方法
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String token = req.getParameter("token");
        String rm = req.getParameter("rm");  // 勾选 on  否则 null


        //检查验证码是否匹配   1.获取服务器中存储的验证码  session
        HttpSession session = req.getSession();
        String code = (String) session.getAttribute("code");

        if (code.equals(token)) { // 根据用户名和密码查询用户信息
            // 根据用户名和密码查询用户信息
            User user = userService.selectByUsernameAndPassword(username, SecureUtil.md5(password));
            if (user == null) {  //  用户不存在
                req.setAttribute("msg", "用户名或密码错误");
                req.getRequestDispatcher("/login.jsp").forward(req, resp);
            } else {     // 登录成功

                // 在会话域中存储用户的信息  用于页面中数据共享
                session.setAttribute("user", user);
                Cookie ck1 = null;
                Cookie ck2 = null;
                Cookie ck3 = null;
                //判定用户是否勾选了记住我
                if ("on".equals(rm)) {
                    // 创建cookie  缓存用户信息到客户端    用户名   密码  记住我的状态
                    ck1 = new Cookie("username", username);
                    ck2 = new Cookie("password", password);
                    ck3 = new Cookie("rm", rm);

                } else {

                    ck1 = new Cookie("username", "");
                    ck2 = new Cookie("password", "");
                    ck3 = new Cookie("rm", rm);

                    //设置cookie的生命周期 为0  立即删除cookie
                    ck1.setMaxAge(0);
                    ck2.setMaxAge(0);
                    ck3.setMaxAge(0);
                }

                resp.addCookie(ck1);
                resp.addCookie(ck2);
                resp.addCookie(ck3);
                // 将页面跳转到主页
                //resp.sendRedirect(req.getContextPath() + "/user?method=selectAll");
                //实现分页
                resp.sendRedirect(req.getContextPath() + "/user?method=selectPage&page=1");
            }
        } else {
            //验证码不正确 返回登录页 继续登录  跳转页面到login.jsp  同时需要携带错误信息
            req.setAttribute("msg", "验证码错误");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }

    }


}
